<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title></title>
	<style type="text/css">
	*{
		margin: 0;
		padding: 0;
	}
	html,body{
		width: 100%;
		height: 100%;
		overflow: hidden;
		text-align: center;
	}
	#gameCanvas{
		border: 2px solid #ff3d17;
		margin: 10px;
		position: relative;
	}
	</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<script type="text/javascript">
Array.prototype.forRound = function(fn,axis,self){
	var that = this, i = axis[0], j=axis[1];
	f(i-1,j-1);f(i-1,j);f(i-1,j+1);f(i,j-1);
	if(self){f(i,j)}f(i,j+1);f(i+1,j-1);f(i+1,j);f(i+1,j+1);
	function f(i,j){
		// 确保不访问非法内存
		if(i < 0 || i >= that.length || j < 0 || j >= that[0].length){
			return 0
		}
		fn(that[i][j],[i,j],that)
	}
}</script>
<script type="text/javascript">
!function(w,e){
	function Game(option){
		Object.assign(this,{
			el: "#gameCanvas",
			mainWidth: 0,
			mainHeight: 0,
			timer: null,
			side: 16,
			innerSide: 16,
			innerOffset: 0,
			map: [],
			nX: 41,
			nY: 41,
		},option)
		this.init()
	}
	Game.prototype.expend = function(obj){Object.assign(this,obj)}
	Game.prototype.expend({
		// 初始化
		init(){
			this.canvas = e.querySelector(this.el)
			this.canvas.isUsed = true
			this.mainWidth = this.side*this.nX
			this.mainHeight = this.side*this.nY
			this.innerOffset = (this.side - this.innerSide) / 2
			this.canvas.setAttribute("width",this.mainWidth)
			this.canvas.setAttribute("height",this.mainHeight)
			this.cx = this.canvas.getContext("2d")
			this.cx.font = "16px 微软雅黑"
			this.cx.textAlign = "center"
			this.cx.textBaseline = "middle"
			this.addEvents()
			this.start()
		},
		// 绑定事件
		addEvents(){
			this.windowKeydown = evt => {
				var k = evt.key
				if(k === "a" || k === "A" || k === "ArrowLeft"){
					this.turn(-1,0)
				}else if(k === "d" || k === "D" || k === "ArrowRight"){
					this.turn(1,0)
				}else if(k === "w" || k === "W" || k === "ArrowUp"){
					this.turn(0,-1)
				}else if(k === "s" || k === "S" || k === "ArrowDown"){
					this.turn(0,1)
				}
			}
			w.addEventListener("keydown",this.windowKeydown)
		},
		start(){
			// 创建点线集合
			var n = 4
			var getAll = (p1,p2) => {
				return Math.floor(Math.sqrt(Math.pow(p1[0]-p2[0],2) + Math.pow(p1[1]-p2[1],2)))
			}
			//检查一棵树是否同时含有 p1, p2 两个点
			var checkHas = (tree,p1,p2) => {
				var num = {p1:0,p2:0}
				var iter = t => {
					if(t.root === p1){
						num.p1 = 1
					}else if(t.root === p2){
						num.p2 = 1
					}
					if(t.child && t.child.length != 0){
						t.child.forEach(c =>iter(c))
					}
				}
				iter(tree)
				return num.p1 + num.p2 === 2
			}
			// 根据节点查找根节点所在树索引
			var findRoot = (trees,p) => {
				var iter = t => {
					t.forEach(t,index,oTrees) => {
						if(t.root === p){
							
						}
						if(t.child && t.child.length != 0){
							t.child.forEach(c =>iter(c))
						}
					}
				}
				iter(trees)
				
			}
			this.pList = []
			this.lineList = []
			for(var i = 0; i < n; i++){
				this.pList.push({
					name: i,
					axis: [
						Math.floor(Math.random() * this.mainWidth),
						Math.floor(Math.random() * this.mainHeight)
					]
				})
			}
			for(var i = 0; i < n; i++){
				for(var j = 0; j < n; j++){
					if(i !== j){
						var able = true
						this.lineList.forEach(l => {
							if((this.pList[i] === l.p1 && this.pList[j] === l.p2) ||
							(this.pList[i] === l.p2 && this.pList[j] === l.p1)){
								able = false
							}
						})
						able && this.lineList.push({
							weight: getAll(this.pList[i].axis,this.pList[j].axis),
							p1: this.pList[i],
							p2: this.pList[j]
						})
					}
				}
			}
			// 将边按权值升序排序
			this.lineList.sort((l1,l2) => {
				return l1.weight - l2.weight
			})
			var trees = []
			// 将所有点作为独立树收入森林
			this.pList.forEach(p => {
				trees.push({
					parent: null,
					root: p,
					child: []
				})
			})
			// 
			this.lineList.forEach(l => {
				// 确保 l 的两端点不在同一颗树上
				var able = true
				trees.forEach(t => {
					if(checkHas(t,l.p1,l.p2)) able = false
				})
				if(able){ // 合并 l 两端点所在的树
					
				}
			})
			
			// 绘制
			this.draw(() => {
				this.cx.fillStyle = '#f06e46'
				this.cx.strokeStyle = "#666"
				this.lineList.forEach(l => {
					this.cx.beginPath()
					this.cx.moveTo(...l.p1.axis)
					this.cx.lineTo(...l.p2.axis)
					this.cx.closePath()
					this.cx.stroke()
					this.cx.fillText(l.weight,(l.p1.axis[0]+l.p2.axis[0])/2,(l.p1.axis[1]+l.p2.axis[1])/2+20)
				})
				this.pList.forEach(p => {
					this.cx.beginPath()
					this.cx.arc(...p.axis,8,0,Math.PI*2)
					this.cx.closePath()
					this.cx.fill()
				})
				
			},true)
		},
		// 销毁实例
		destroy(){
			this.timer && clearInterval(this.timer)
			this.cx.clearRect(0,0,this.mainWidth,this.mainHeight)
			this.canvas.isUsed = false
			w.removeEventListener("keydown",this.windowKeydown)
		},
		// 主绘制函数
		draw(frame,isSingle){
			this.timer && clearInterval(this.timer)
			var main = () => {
				this.cx.save()
				this.cx.clearRect(0,0,this.mainWidth,this.mainHeight)
				frame()
				this.cx.restore()
			}
			if(isSingle){
				main()
			}else{
				this.timer = setInterval(main,200)
			}
		}
	})
	w.Game = Game
}(window,document)
var gameDemo = new Game()
	
</script>
</body>
</html>